package com.example.javabasic.thread.classone.demo5;

import java.util.*;

public class BooleanLock implements Lock {
    //锁状态  true  上锁  false  释放锁
    private Boolean blocked;
    //被阻塞线程集合
    private Set<Thread> blockedThreadCollection = new HashSet<>();
    // 记录是哪个线程上的锁   只能被这个线程自己解锁
    private Thread lockedThread;

    public BooleanLock(){
        this.blocked = false;
    }

    public BooleanLock(Boolean blocked) {
        this.blocked = blocked;
    }

    @Override
    public synchronized void lock() throws InterruptedException {
        blockedThreadCollection.add(Thread.currentThread());
        while(blocked){
            //让线程等待
            this.wait();
        }
        System.out.println(Thread.currentThread().getName()+" 线程被释放>>" );
        this.blocked = true;
        this.lockedThread = Thread.currentThread();
    }

    /**
     * 超时获取锁
     * @param milles
     * @throws InterruptedException
     * @throws TimeOutException
     */
    @Override
    public synchronized void lock(long milles) throws InterruptedException, TimeOutException {
        if(milles <= 0){
            wait();
        }
        //超时时间
        long hasRemaining = milles;
        //结束时间
        long endTime = System.currentTimeMillis()+ milles;


        //如果是被锁定状态, 则添加到 阻塞集合  blockedThreadCollection中
        while (blocked) {
            if (hasRemaining<=0){
                throw new TimeOutException(Thread.currentThread().getName()+" 线程获取锁超时");
            }

            blockedThreadCollection.add(Thread.currentThread());
            //让线程等待
            this.wait(milles);
            hasRemaining =  endTime - System.currentTimeMillis();
        }
        blockedThreadCollection.remove(Thread.currentThread());
        Optional.of(Thread.currentThread().getName()+" 线程争取到锁并从阻塞队列移除---" ).ifPresent(System.out::println);
        this.blocked = true;
        this.lockedThread = Thread.currentThread();
    }

    @Override
    public synchronized void unLock() {
        //如果是当前线程自己解锁  可以执行  如果不是 那直接忽略
        if(lockedThread == Thread.currentThread()){
            //释放锁
            this.blocked = false;
            System.out.println(Thread.currentThread().getName() + " 释放锁,唤醒所有线程");
            this.notifyAll();
        }
    }

    @Override
    public Collection<Thread> getBlockedThreads() {
        //返回不可修改的集合 让其他地方的内容无法对其进行修改
        return Collections.unmodifiableCollection(blockedThreadCollection);
    }

    @Override
    public int getBlockedSize() {
        return blockedThreadCollection.size();
    }
}
